Skip to content

Account for unaddressed funcs in GlobalEffects#8644

Open
stevenfontanella wants to merge 20 commits into
mainfrom
indirect-effects-address
Open

Account for unaddressed funcs in GlobalEffects#8644
stevenfontanella wants to merge 20 commits into
mainfrom
indirect-effects-address

Conversation

@stevenfontanella
Copy link
Copy Markdown
Member

@stevenfontanella stevenfontanella commented Apr 23, 2026

Part of #8615. We currently union the effects of all functions of a given type when computing the effects for indirect calls. Make this more precise by excluding effects of functions that never have their address taken.

Continued from #8628 which was accidentally merged.

@stevenfontanella stevenfontanella changed the title Indirect effects address Improve indirect call effects in GlobalEffects Apr 23, 2026
@stevenfontanella stevenfontanella marked this pull request as ready for review April 23, 2026 20:01
@stevenfontanella stevenfontanella requested a review from a team as a code owner April 23, 2026 20:01
Comment thread src/passes/GlobalEffects.cpp Outdated
Comment thread src/passes/GlobalEffects.cpp Outdated
an indirect call and we don't need to include its effects in indirect calls.
*/
std::unordered_set<Function*> getAddressedFuncs(Module& module) {
struct AddressedFuncsWalker : PostWalker<AddressedFuncsWalker> {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might as well make this a WalkerPass so it can be run on all the functions in parallel. Then instead of walkModule below, you would use walkModuleCode. Alternatively you could use ModuleUtils::ParallelFunctionAnalysis + walkModuleCode.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 on using ParallelFunctionAnalysis

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WalkerPass can also run in parallel:

if (isFunctionParallel()) {
. Since we want to handle all code (functions + non-functions) I guess WalkerPass seems more appropriate here? Changed it to that with isFunctionParallel set to true.

Base automatically changed from indirect-effects-scc to main April 24, 2026 21:36
@stevenfontanella stevenfontanella force-pushed the indirect-effects-address branch from cafaa9b to dd80924 Compare April 24, 2026 22:10
Copy link
Copy Markdown
Member

@aheejin aheejin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM % some nits + Thomas's comments

Comment thread test/lit/passes/global-effects-closed-world.wast Outdated
Comment thread test/lit/passes/global-effects-closed-world.wast Outdated
Comment thread src/passes/GlobalEffects.cpp Outdated
Comment thread src/passes/GlobalEffects.cpp Outdated
an indirect call and we don't need to include its effects in indirect calls.
*/
std::unordered_set<Function*> getAddressedFuncs(Module& module) {
struct AddressedFuncsWalker : PostWalker<AddressedFuncsWalker> {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 on using ParallelFunctionAnalysis

Comment thread src/passes/GlobalEffects.cpp Outdated
statements in our IR, but we check separately for funcs that appear in
`ref.func`).
- It's exported, because it may flow back to us as a reference.
- It's imported, which implies it is `elem declare`d.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it's only me but 'it is elem declared' sounds a little confusing (because it is not, even though I get what you mean). How about just saying imported functions can be passed a reference (as you did with the exported functions)?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rephrased the comment

@stevenfontanella
Copy link
Copy Markdown
Member Author

Will continue this after #8625 is in.

@stevenfontanella stevenfontanella changed the title Improve indirect call effects in GlobalEffects Account for unaddressed func in GlobalEffects May 20, 2026
@stevenfontanella stevenfontanella changed the title Account for unaddressed func in GlobalEffects Account for unaddressed funcs in GlobalEffects May 20, 2026
@stevenfontanella stevenfontanella force-pushed the indirect-effects-address branch from dd80924 to 0af5402 Compare May 27, 2026 18:15
@stevenfontanella
Copy link
Copy Markdown
Member Author

Have a few more updates to do, will update after I'm done.

Also, apologies for the force-push. I've been trying out JJ which force-pushes by default. I tried merging via JJ but it still chose to force-push for some reason. Will look into disabling this locally.

Comment thread src/passes/GlobalEffects.cpp Outdated
@stevenfontanella
Copy link
Copy Markdown
Member Author

Should be good now, PTAL

Comment thread src/passes/GlobalEffects.cpp Outdated
Comment on lines +50 to +52
// - It appears in an `elem` segment (note that we already ignore `elem declare`
// statements in our IR, but we check separately for funcs that appear in
// `ref.func`).
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This condition is subsumed by the the previous condition, so is redundant. Maybe that's what the note is saying, but I think we can just remove this entirely.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the point but included a small note on it still to make it clear how it maps to Wasm (we drop elem statements but in the source Wasm they should still be considered referenced).

Comment thread src/passes/GlobalEffects.cpp Outdated
Comment thread src/passes/GlobalEffects.cpp Outdated
Comment thread src/passes/GlobalEffects.cpp Outdated
std::unordered_set<Function*> addressedFuncs;
AddressedFuncsWalker walker(addressedFuncs);
walker.walkModuleCode(&module);
walker.walkModule(&module);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't going to traverse the module in parallel. You need to call .run() on the pass or explicitly use a PassRunner if you want it to run in parallel. However, having all the threads updating the single addressedFuncs set in parallel would not be safe. Safe options include collecting a separate set for each function in parallel (possibly using ParallelFunctionAnalysis) and then combining them, or using a std::unordered_map<Name, std::atomic<bool>> that is pre-filled with an entry for each function so that the threads do not race to grow the map.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Included it in the existing pass to avoid having to create a ParallelFunctionAnalysis with the same logic.

Comment thread test/lit/passes/global-effects-closed-world-simplify-locals.wast Outdated
Comment thread src/passes/GlobalEffects.cpp Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants